﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace HexTileBoard
{
    public class QuadtreeLeaf
    {
        // Contained objects
        private Dictionary<HexTileBase, List<TileSimple>> containedBaseTiles;     // List of base tiles contained in this quadtree leaf, used for instanced drawing.
        private Dictionary<HexTileNaturalModifier, List<TileSimple>> containedNaturalModifiers; // List of natural modifier locations
        private Dictionary<HexTileManMadeModifier, List<TileSimple>> containedManmadeModifiers; // list of all manmade modifiers
        private Dictionary<PlayerColor, List<TileSimple>> containedColors;

        // possible to just draw with Dictionary<key, List<Matrix>>

        // Leaf components
        private QuadtreeLeaf[] childLeaves;     // Always 8
        private BoundingBox ContainerBox;
        //private Vector2 quadMin, quadMax;       // Maximum bounding dimensions for this leaf.
        private int nodeDepth;                // Depth of this leaf in the tree.
        public int NodeDepth
        {
            get { return nodeDepth; }
        }

        // Tree components
        private int treeDepth;                // Depth of the tree.
        public int TreeDepth
        {
            get { return treeDepth; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_boundingBox">A 1-height bounding box, simulating the 2D XZ quadtree.</param>
        /// <param name="p_nodeDepth"></param>
        /// <param name="p_treeDepth"></param>
        public QuadtreeLeaf(BoundingBox _boundingBox, int p_nodeDepth, int p_treeDepth)
        {
            this.childLeaves = null;
            this.ContainerBox = _boundingBox;
            this.ContainerBox.Max.Y = 300;
            this.ContainerBox.Min.Y = -100;

            this.nodeDepth = p_nodeDepth;
            this.treeDepth = p_treeDepth;

            if (this.nodeDepth != p_treeDepth)
                Split();
            else
            {
                // Initialize containers for componets drawn with instancing
                this.containedBaseTiles = new Dictionary<HexTileBase, List<TileSimple>>();
                foreach (HexTileBase b in InstancedDictionaries.baseListProvider)
                {
                    this.containedBaseTiles[b] = new List<TileSimple>();
                }

                this.containedNaturalModifiers = new Dictionary<HexTileNaturalModifier, List<TileSimple>>();
                foreach (HexTileNaturalModifier n in InstancedDictionaries.naturalListProvider)
                {
                    this.containedNaturalModifiers[n] = new List<TileSimple>();
                }

                this.containedManmadeModifiers = new Dictionary<HexTileManMadeModifier, List<TileSimple>>();
                foreach (HexTileManMadeModifier m in InstancedDictionaries.manmadeListProvider)
                {
                    this.containedManmadeModifiers[m] = new List<TileSimple>();
                }

                this.containedColors = new Dictionary<PlayerColor, List<TileSimple>>();
                foreach (PlayerColor p in InstancedDictionaries.colorListProvider)
                {
                    this.containedColors[p] = new List<TileSimple>();
                }
            }
        }

        public void GetValues(ref int influence1, ref int influence2, ref int influence3)
        {

            if (this.nodeDepth == this.treeDepth)    // only add to the bottom of the tree
            {
                influence1 += this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower1].Count;
                influence2 += this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower2].Count;
                influence3 += this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower3].Count;
                return;
            }
            else
            {
                for (int i = 0; i < 4; i++)
                {
                    childLeaves[i].GetValues(ref influence1, ref influence2, ref influence3);
                }
                return;
            }
        }

        public void DrawVisibleInstancedListsByDiscovery(GameTime gameTime, SimpleCamera camera, bool _creatingShadows)
        {
            //BoardConstructor.branchesVisited++;

            // If our camera intersects this box...
            if (camera.ViewFrustum.Intersects(this.ContainerBox))
            {
                // ... and we are at the child leaves at the bottom of the tree
                if (this.nodeDepth == treeDepth)
                {
                    // ... so loop through dictionaries and draw.
                    // On the XBox, each model type IN EACH quadtree leaf needs a vertex buffer, so for now, just hard case it all to get it done. Look at old file for how to loop.
                    // ----------------------------------------------------------------
                    // Draw color tiles
                    // ----------------------------------------------------------------
                    // Blue
                    Array.Resize(ref InstancedDictionaries.colorModels[PlayerColor.Blue].instanceTransforms, this.containedColors[PlayerColor.Blue].Count);
                    for (int i = 0; i < this.containedColors[PlayerColor.Blue].Count; i++)
                    {
                        InstancedDictionaries.colorModels[PlayerColor.Blue].instanceTransforms[i] = Matrix.CreateScale(1.0f, 6.0f * this.containedColors[PlayerColor.Blue][i].value, 1.0f) * Matrix.CreateTranslation(new Vector3(0, 16 * (this.containedColors[PlayerColor.Blue][i].value), 0)) * this.containedColors[PlayerColor.Blue][i].ModelMatrix;
                        //InstancedDictionaries.colorModels[PlayerColor.Blue].instanceTransforms[i] = this.containedColors[PlayerColor.Blue][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.colorModels[PlayerColor.Blue].instancedModel, InstancedDictionaries.colorModels[PlayerColor.Blue].instancedModelBones, InstancedDrawing.instanceVertexBufferBlue, InstancedDictionaries.colorModels[PlayerColor.Blue].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.colorModels[PlayerColor.Blue].instancedModel, InstancedDictionaries.colorModels[PlayerColor.Blue].instancedModelBones, InstancedDrawing.instanceVertexBufferBlue, InstancedDictionaries.colorModels[PlayerColor.Blue].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "HardwareInstancingNoShadow", true, 1.0f);

                    // Red
                    Array.Resize(ref InstancedDictionaries.colorModels[PlayerColor.Red].instanceTransforms, this.containedColors[PlayerColor.Red].Count);
                    for (int i = 0; i < this.containedColors[PlayerColor.Red].Count; i++)
                    {
                        InstancedDictionaries.colorModels[PlayerColor.Red].instanceTransforms[i] = Matrix.CreateScale(1.0f, 4.0f * this.containedColors[PlayerColor.Red][i].value, 1.0f) * Matrix.CreateTranslation(new Vector3(0, 10 * (this.containedColors[PlayerColor.Red][i].value), 0)) * this.containedColors[PlayerColor.Red][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.colorModels[PlayerColor.Red].instancedModel, InstancedDictionaries.colorModels[PlayerColor.Red].instancedModelBones, InstancedDrawing.instanceVertexBufferRed, InstancedDictionaries.colorModels[PlayerColor.Red].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.colorModels[PlayerColor.Red].instancedModel, InstancedDictionaries.colorModels[PlayerColor.Red].instancedModelBones, InstancedDrawing.instanceVertexBufferRed, InstancedDictionaries.colorModels[PlayerColor.Red].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "HardwareInstancingNoShadow", true, 1.0f);

                    // Yellow
                    Array.Resize(ref InstancedDictionaries.colorModels[PlayerColor.Yellow].instanceTransforms, this.containedColors[PlayerColor.Yellow].Count);
                    for (int i = 0; i < this.containedColors[PlayerColor.Yellow].Count; i++)
                    {
                        InstancedDictionaries.colorModels[PlayerColor.Yellow].instanceTransforms[i] = Matrix.CreateScale(1.0f, 4.0f * this.containedColors[PlayerColor.Yellow][i].value, 1.0f) * Matrix.CreateTranslation(new Vector3(0, 10 * (this.containedColors[PlayerColor.Yellow][i].value), 0)) * this.containedColors[PlayerColor.Yellow][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.colorModels[PlayerColor.Yellow].instancedModel, InstancedDictionaries.colorModels[PlayerColor.Yellow].instancedModelBones, InstancedDrawing.instanceVertexBufferYellow, InstancedDictionaries.colorModels[PlayerColor.Yellow].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.colorModels[PlayerColor.Yellow].instancedModel, InstancedDictionaries.colorModels[PlayerColor.Yellow].instancedModelBones, InstancedDrawing.instanceVertexBufferYellow, InstancedDictionaries.colorModels[PlayerColor.Yellow].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "HardwareInstancingNoShadow", true, 1.0f);

                    // Green
                    Array.Resize(ref InstancedDictionaries.colorModels[PlayerColor.Green].instanceTransforms, this.containedColors[PlayerColor.Green].Count);
                    for (int i = 0; i < this.containedColors[PlayerColor.Green].Count; i++)
                    {
                        InstancedDictionaries.colorModels[PlayerColor.Green].instanceTransforms[i] = Matrix.CreateScale(1.0f, 4.0f * this.containedColors[PlayerColor.Green][i].value, 1.0f) * Matrix.CreateTranslation(new Vector3(0, 10 * (this.containedColors[PlayerColor.Green][i].value), 0)) * this.containedColors[PlayerColor.Green][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.colorModels[PlayerColor.Green].instancedModel, InstancedDictionaries.colorModels[PlayerColor.Green].instancedModelBones, InstancedDrawing.instanceVertexBufferGreen, InstancedDictionaries.colorModels[PlayerColor.Green].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.colorModels[PlayerColor.Green].instancedModel, InstancedDictionaries.colorModels[PlayerColor.Green].instancedModelBones, InstancedDrawing.instanceVertexBufferGreen, InstancedDictionaries.colorModels[PlayerColor.Green].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "HardwareInstancingNoShadow", true, 1.0f);

                    // ----------------------------------------------------------------
                    // Draw base tiles
                    // ----------------------------------------------------------------
                    // Grass
                    Array.Resize(ref InstancedDictionaries.baseModels[HexTileBase.Grass].instanceTransforms, this.containedBaseTiles[HexTileBase.Grass].Count);
                    for (int i = 0; i < this.containedBaseTiles[HexTileBase.Grass].Count; i++)
                    {
                        InstancedDictionaries.baseModels[HexTileBase.Grass].instanceTransforms[i] = this.containedBaseTiles[HexTileBase.Grass][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.baseModels[HexTileBase.Grass].instancedModel, InstancedDictionaries.baseModels[HexTileBase.Grass].instancedModelBones, InstancedDrawing.instanceVertexBufferGrass, InstancedDictionaries.baseModels[HexTileBase.Grass].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.baseModels[HexTileBase.Grass].instancedModel, InstancedDictionaries.baseModels[HexTileBase.Grass].instancedModelBones, InstancedDrawing.instanceVertexBufferGrass, InstancedDictionaries.baseModels[HexTileBase.Grass].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    // Sand
                    Array.Resize(ref InstancedDictionaries.baseModels[HexTileBase.Sand].instanceTransforms, this.containedBaseTiles[HexTileBase.Sand].Count);
                    for (int i = 0; i < this.containedBaseTiles[HexTileBase.Sand].Count; i++)
                    {
                        InstancedDictionaries.baseModels[HexTileBase.Sand].instanceTransforms[i] = this.containedBaseTiles[HexTileBase.Sand][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.baseModels[HexTileBase.Sand].instancedModel, InstancedDictionaries.baseModels[HexTileBase.Sand].instancedModelBones, InstancedDrawing.instanceVertexBufferSand, InstancedDictionaries.baseModels[HexTileBase.Sand].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.baseModels[HexTileBase.Sand].instancedModel, InstancedDictionaries.baseModels[HexTileBase.Sand].instancedModelBones, InstancedDrawing.instanceVertexBufferSand, InstancedDictionaries.baseModels[HexTileBase.Sand].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    // Water
                    Array.Resize(ref InstancedDictionaries.baseModels[HexTileBase.Water].instanceTransforms, this.containedBaseTiles[HexTileBase.Water].Count);
                    for (int i = 0; i < this.containedBaseTiles[HexTileBase.Water].Count; i++)
                    {
                        InstancedDictionaries.baseModels[HexTileBase.Water].instanceTransforms[i] = this.containedBaseTiles[HexTileBase.Water][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.baseModels[HexTileBase.Water].instancedModel, InstancedDictionaries.baseModels[HexTileBase.Water].instancedModelBones, InstancedDrawing.instanceVertexBufferWater, InstancedDictionaries.baseModels[HexTileBase.Water].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.baseModels[HexTileBase.Water].instancedModel, InstancedDictionaries.baseModels[HexTileBase.Water].instancedModelBones, InstancedDrawing.instanceVertexBufferWater, InstancedDictionaries.baseModels[HexTileBase.Water].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    // ----------------------------------------------------------------
                    // Draw natural modifiers
                    // ----------------------------------------------------------------
                    // Hills
                    //Array.Resize(ref InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms, this.containedNaturalModifiers[HexTileNaturalModifier.Hill2].Count);
                    //for (int i = 0; i < this.containedNaturalModifiers[HexTileNaturalModifier.Hill2].Count; i++)
                    //{
                    //    InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms[i] = this.containedNaturalModifiers[HexTileNaturalModifier.Hill2][i].naturalMatrix;
                    //}

                    //if (_creatingShadows)
                    //    InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModelBones, InstancedDrawing.instanceVertexBufferHill1, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    //else
                    //    InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModelBones, InstancedDrawing.instanceVertexBufferHill1, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    Array.Resize(ref InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms, this.containedNaturalModifiers[HexTileNaturalModifier.Hill2].Count);
                    for (int i = 0; i < this.containedNaturalModifiers[HexTileNaturalModifier.Hill2].Count; i++)
                    {
                        InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms[i] = this.containedNaturalModifiers[HexTileNaturalModifier.Hill2][i].naturalMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModelBones, InstancedDrawing.instanceVertexBufferHill2, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModelBones, InstancedDrawing.instanceVertexBufferHill2, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    //Array.Resize(ref InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms, this.containedNaturalModifiers[HexTileNaturalModifier.Hill2].Count);
                    //for (int i = 0; i < this.containedNaturalModifiers[HexTileNaturalModifier.Hill2].Count; i++)
                    //{
                    //    InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms[i] = this.containedNaturalModifiers[HexTileNaturalModifier.Hill2][i].naturalMatrix;
                    //}

                    //if (_creatingShadows)
                    //    InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModelBones, InstancedDrawing.instanceVertexBufferHill3, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    //else
                    //    InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instancedModelBones, InstancedDrawing.instanceVertexBufferHill3, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Hill2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    // Mountains
                    Array.Resize(ref InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain3].instanceTransforms, this.containedNaturalModifiers[HexTileNaturalModifier.Mountain3].Count);
                    for (int i = 0; i < this.containedNaturalModifiers[HexTileNaturalModifier.Mountain3].Count; i++)
                    {
                        InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain3].instanceTransforms[i] = this.containedNaturalModifiers[HexTileNaturalModifier.Mountain3][i].naturalMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain3].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain3].instancedModelBones, InstancedDrawing.instanceVertexBufferMountain3, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain3].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain3].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain3].instancedModelBones, InstancedDrawing.instanceVertexBufferMountain3, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain3].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    Array.Resize(ref InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain2].instanceTransforms, this.containedNaturalModifiers[HexTileNaturalModifier.Mountain2].Count);
                    for (int i = 0; i < this.containedNaturalModifiers[HexTileNaturalModifier.Mountain2].Count; i++)
                    {
                        InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain2].instanceTransforms[i] = this.containedNaturalModifiers[HexTileNaturalModifier.Mountain2][i].naturalMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain2].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain2].instancedModelBones, InstancedDrawing.instanceVertexBufferMountain2, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain2].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain2].instancedModelBones, InstancedDrawing.instanceVertexBufferMountain2, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    Array.Resize(ref InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain1].instanceTransforms, this.containedNaturalModifiers[HexTileNaturalModifier.Mountain1].Count);
                    for (int i = 0; i < this.containedNaturalModifiers[HexTileNaturalModifier.Mountain1].Count; i++)
                    {
                        InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain1].instanceTransforms[i] = this.containedNaturalModifiers[HexTileNaturalModifier.Mountain1][i].naturalMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain1].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain1].instancedModelBones, InstancedDrawing.instanceVertexBufferMountain1, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain1].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain1].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain1].instancedModelBones, InstancedDrawing.instanceVertexBufferMountain1, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Mountain1].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    // Trees
                    Array.Resize(ref InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instanceTransforms, this.containedNaturalModifiers[HexTileNaturalModifier.Trees1].Count);
                    for (int i = 0; i < this.containedNaturalModifiers[HexTileNaturalModifier.Trees1].Count; i++)
                    {
                        InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instanceTransforms[i] = this.containedNaturalModifiers[HexTileNaturalModifier.Trees1][i].naturalMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instancedModelBones, InstancedDrawing.instanceVertexBufferTrees1, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instancedModelBones, InstancedDrawing.instanceVertexBufferTrees1, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    //Array.Resize(ref InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instanceTransforms, this.containedNaturalModifiers[HexTileNaturalModifier.Trees1].Count);
                    //for (int i = 0; i < this.containedNaturalModifiers[HexTileNaturalModifier.Trees1].Count; i++)
                    //{
                    //    InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instanceTransforms[i] = this.containedNaturalModifiers[HexTileNaturalModifier.Trees1][i].naturalMatrix;
                    //}

                    //if (_creatingShadows)
                    //    InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instancedModelBones, InstancedDrawing.instanceVertexBufferTrees2, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    //else
                    //    InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instancedModelBones, InstancedDrawing.instanceVertexBufferTrees2, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Trees1].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    // Wheat
                    Array.Resize(ref InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Wheat].instanceTransforms, this.containedNaturalModifiers[HexTileNaturalModifier.Wheat].Count);
                    for (int i = 0; i < this.containedNaturalModifiers[HexTileNaturalModifier.Wheat].Count; i++)
                    {
                        InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Wheat].instanceTransforms[i] = this.containedNaturalModifiers[HexTileNaturalModifier.Wheat][i].naturalMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Wheat].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Wheat].instancedModelBones, InstancedDrawing.instanceVertexBufferWheat, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Wheat].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Wheat].instancedModel, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Wheat].instancedModelBones, InstancedDrawing.instanceVertexBufferWheat, InstancedDictionaries.naturalModifierModels[HexTileNaturalModifier.Wheat].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);


                    // ----------------------------------------------------------------
                    // Draw manmade modifiers
                    // ----------------------------------------------------------------
                    // Bridge
                    Array.Resize(ref InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.Bridge].instanceTransforms, this.containedManmadeModifiers[HexTileManMadeModifier.Bridge].Count);
                    for (int i = 0; i < this.containedManmadeModifiers[HexTileManMadeModifier.Bridge].Count; i++)
                    {
                        InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.Bridge].instanceTransforms[i] = this.containedManmadeModifiers[HexTileManMadeModifier.Bridge][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.Bridge].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.Bridge].instancedModelBones, InstancedDrawing.instanceVertexBufferBridge, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.Bridge].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.Bridge].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.Bridge].instancedModelBones, InstancedDrawing.instanceVertexBufferBridge, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.Bridge].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    // DefensiveTower
                    Array.Resize(ref InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.DefensiveTower].instanceTransforms, this.containedManmadeModifiers[HexTileManMadeModifier.DefensiveTower].Count);
                    for (int i = 0; i < this.containedManmadeModifiers[HexTileManMadeModifier.DefensiveTower].Count; i++)
                    {
                        InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.DefensiveTower].instanceTransforms[i] = this.containedManmadeModifiers[HexTileManMadeModifier.DefensiveTower][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.DefensiveTower].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.DefensiveTower].instancedModelBones, InstancedDrawing.instanceVertexBufferDefensiveTower, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.DefensiveTower].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.DefensiveTower].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.DefensiveTower].instancedModelBones, InstancedDrawing.instanceVertexBufferDefensiveTower, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.DefensiveTower].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    // InfluenceTower1
                    Array.Resize(ref InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instanceTransforms, this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower1].Count);
                    for (int i = 0; i < this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower1].Count; i++)
                    {
                        InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instanceTransforms[i] = this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower1][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower1, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    else
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower1, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);

                    // InfluenceTower2
                    // Because of bad modeling, the towers are broken up and must be drawn multiple times
                    Array.Resize(ref InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instanceTransforms, this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower2].Count);
                    for (int i = 0; i < this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower2].Count; i++)
                    {
                        InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instanceTransforms[i] = this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower2][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                    {
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower2, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower2, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    }
                    else
                    {
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower2, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower2, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);
                    }

                    // InfluenceTower3
                    Array.Resize(ref InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instanceTransforms, this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower3].Count);
                    for (int i = 0; i < this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower3].Count; i++)
                    {
                        InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instanceTransforms[i] = this.containedManmadeModifiers[HexTileManMadeModifier.InfluenceTower3][i].ModelMatrix;
                    }

                    if (_creatingShadows)
                    {
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower3, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower3, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower3, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "CreateShadowMapHardwareInstancing", true, 1.0f);
                    }
                    else
                    {
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower1].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower3, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower2].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower3, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);
                        InstancedDrawing.DrawModelHardwareInstancing(InstancedDictionaries.instancedGraphicsDevice, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instancedModel, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instancedModelBones, InstancedDrawing.instanceVertexBufferInfluenceTower3, InstancedDictionaries.manMadeModifierModels[HexTileManMadeModifier.InfluenceTower3].instanceTransforms, camera.ViewMatrix, camera.ProjectionMatrix, "DrawWithShadowMapHardwareInstancing3x3", false, 1.0f);
                    }
                }
                else    // ... else search our children through recursion.
                {
                    for (int i = 0; i < 4; i++)
                        childLeaves[i].DrawVisibleInstancedListsByDiscovery(gameTime, camera, _creatingShadows);
                }
            }
            else
            {
                return;
            }
        }

        public void RetrieveIntersectedObjects(Ray cursorRay, ref List<TileSimple> retrievedTiles)
        {
            // If our camera intersects this box...
            if (cursorRay.Intersects(this.ContainerBox) != null)
            {
                // ... and we are at the child leaves at the bottom of the tree
                if (this.nodeDepth == treeDepth)
                {
                    // ... so loop through dictionaries and draw.
                    foreach (HexTileBase b in InstancedDictionaries.baseListProvider)
                    {
                        for (int i = 0; i < this.containedBaseTiles[b].Count; i++)
                        {
                            if (this.containedBaseTiles[b][i].BS.Intersects(cursorRay) != null)
                            {
                                // add to list
                                retrievedTiles.Add(this.containedBaseTiles[b][i]);
                            }
                        }
                    }
                }
                else    // ... else search our children through recursion.
                {
                    for (int i = 0; i < 4; i++)
                        childLeaves[i].RetrieveIntersectedObjects(cursorRay, ref retrievedTiles);
                }
            }
            else
            {
                return;
            }
        }

        public void RetrieveClosestObject(Ray cursorRay, ref TileSimple closestTile)
        {
            // If our camera intersects this box...
            if (cursorRay.Intersects(this.ContainerBox) != null)
            {
                // ... and we are at the child leaves at the bottom of the tree
                if (this.nodeDepth == treeDepth)
                {
                    // ... so loop through dictionaries and draw.
                    foreach (HexTileBase b in InstancedDictionaries.baseListProvider)
                    {
                        for (int i = 0; i < this.containedBaseTiles[b].Count; i++)
                        {
                            if (this.containedBaseTiles[b][i].BS.Intersects(cursorRay) != null)
                            {
                                if (closestTile == null)
                                {
                                    closestTile = this.containedBaseTiles[b][i];
                                }
                                else if (Vector3.Distance(cursorRay.Position, closestTile.Position) > Vector3.Distance(cursorRay.Position, this.containedBaseTiles[b][i].Position))
                                {
                                    closestTile = this.containedBaseTiles[b][i];
                                }
                            }
                        }
                    }
                }
                else    // ... else search our children through recursion.
                {
                    for (int i = 0; i < 4; i++)
                        childLeaves[i].RetrieveClosestObject(cursorRay, ref closestTile);
                }
            }
            else
            {
                return;
            }
        }

        public bool AddColorTile(TileSimple hexTile)
        {
            if (hexTile.BS.Intersects(this.ContainerBox))
            {
                if (this.nodeDepth == this.treeDepth)    // only add to the bottom of the tree
                {
                    this.containedColors[hexTile.tileOwner].Add(hexTile);
                    return true;
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        if (childLeaves[i].AddColorTile(hexTile))
                        {
                            return true;
                        }
                    }
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        public bool AddBaseTile(TileSimple hexTile)
        {
            if (hexTile.BS.Intersects(this.ContainerBox))
            {
                if (this.nodeDepth == this.treeDepth)    // only add to the bottom of the tree
                {
                    this.containedBaseTiles[hexTile.TileBase].Add(hexTile);
                    return true;
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        if (childLeaves[i].AddBaseTile(hexTile))
                        {
                            return true;
                        }
                    }
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        public bool AddNaturalModifier(TileSimple baseTile)
        {
            if (baseTile.BS.Intersects(this.ContainerBox))
            {
                if (this.nodeDepth == this.treeDepth)    // only add to the bottom of the tree
                {
                    // Randomize the rotation of natural objects, if not wheat
                    Matrix r = Matrix.Identity;
                    if (baseTile.NaturalModifier != HexTileNaturalModifier.Wheat)
                    {
                        baseTile.naturalRotationAmount = BoardConstructor.random.Next(0, 700) / 100.0f;
                        r = Matrix.CreateRotationY(baseTile.naturalRotationAmount);
                    }
                    baseTile.naturalMatrix = r * baseTile.ModelMatrix;

                    this.containedNaturalModifiers[baseTile.NaturalModifier].Add(baseTile);
                    return true;
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        if (childLeaves[i].AddNaturalModifier(baseTile))
                        {
                            return true;
                        }
                    }
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        public bool AddManmadeModifier(TileSimple baseTile)
        {
            if (baseTile.BS.Intersects(this.ContainerBox))
            {
                if (this.nodeDepth == this.treeDepth)    // only add to the bottom of the tree
                {
                    this.containedManmadeModifiers[baseTile.ManMadeModifier].Add(baseTile);
                    return true;
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        if (childLeaves[i].AddManmadeModifier(baseTile))
                        {
                            return true;
                        }
                    }
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        public bool RemoveNaturalModifier(TileSimple baseTile)
        {
            if (baseTile.BS.Intersects(this.ContainerBox))
            {
                if (this.nodeDepth == this.treeDepth)    // only add to the bottom of the tree
                {
                    // remove the rotations added for natural modifiers
                    this.containedNaturalModifiers[baseTile.PreviousNaturalModifier].Remove(baseTile);
                    return true;
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        if (childLeaves[i].RemoveNaturalModifier(baseTile))
                        {
                            return true;
                        }
                    }
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        public bool RemoveManMadeModifier(TileSimple baseTile)
        {
            if (baseTile.BS.Intersects(this.ContainerBox))
            {
                if (this.nodeDepth == this.treeDepth)    // only add to the bottom of the tree
                {
                    // remove the rotations added for natural modifiers
                    this.containedManmadeModifiers[baseTile.PreviousManMadeModifier].Remove(baseTile);
                    return true;
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        if (childLeaves[i].RemoveManMadeModifier(baseTile))
                        {
                            return true;
                        }
                    }
                    return false;
                }
            }
            else
            {
                return false;
            }
        }


        /// <summary>
        /// Removes a colored tile from the draw queue.
        /// </summary>
        /// <param name="baseTile"></param>
        /// <param name="previousOwner">Needed as the tile's owner is cleared before the quadtree is removed.</param>
        /// <returns></returns>
        public bool RemoveColor(TileSimple baseTile, PlayerColor previousOwner)
        {
            if (baseTile.BS.Intersects(this.ContainerBox))
            {
                if (this.nodeDepth == this.treeDepth)    // only add to the bottom of the tree
                {
                    // remove the rotations added for natural modifiers
                    this.containedColors[previousOwner].Remove(baseTile);
                    return true;
                }
                else
                {
                    for (int i = 0; i < 4; i++)
                    {
                        if (childLeaves[i].RemoveColor(baseTile, previousOwner))
                        {
                            return true;
                        }
                    }
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        private void Split()
        {
            Vector3 half = ContainerBox.Max - ContainerBox.Min;
            half *= 0.5f;
            Vector3 halfx = Vector3.UnitX * half;
            Vector3 halfz = Vector3.UnitZ * half;

            childLeaves = new QuadtreeLeaf[4];
            childLeaves[0] = new QuadtreeLeaf(new BoundingBox(ContainerBox.Min, ContainerBox.Min + half), this.nodeDepth + 1, this.treeDepth);
            childLeaves[1] = new QuadtreeLeaf(new BoundingBox(ContainerBox.Min + halfx, ContainerBox.Max - halfz), this.nodeDepth + 1, this.treeDepth);
            childLeaves[2] = new QuadtreeLeaf(new BoundingBox(ContainerBox.Min + halfz, ContainerBox.Max - halfx), this.nodeDepth + 1, this.treeDepth);
            childLeaves[3] = new QuadtreeLeaf(new BoundingBox(ContainerBox.Min + half, ContainerBox.Max), this.nodeDepth + 1, this.treeDepth);


            //Vector2 half = quadMax - quadMin;
            //half *= 0.5f;
            //Vector2 halfx = Vector2.UnitX * half;
            //Vector2 halfy = Vector2.UnitY * half;

            //childLeaves = new QuadtreeLeaf[4];
            //childLeaves[0] = new QuadtreeLeaf(quadMin, quadMin + half, (short)(this.nodeDepth + 1), this.treeDepth);
            //childLeaves[1] = new QuadtreeLeaf(quadMin + halfx, quadMax - halfy, (short)(this.nodeDepth + 1), this.treeDepth);
            //childLeaves[2] = new QuadtreeLeaf(quadMin + halfy, quadMax - halfx, (short)(this.nodeDepth + 1), this.treeDepth);
            //childLeaves[3] = new QuadtreeLeaf(quadMin + half, quadMax, (short)(this.nodeDepth + 1), this.treeDepth);
        }
    }
}
